package com.hyhy.hycloud.commons.support.repository;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

import java.io.Serializable;
import java.util.List;

/**
 * @author lanpengfei
 * @date 2019-03-23
 */
public class QuerySimpleMongoRepository<T, ID extends Serializable> extends SimpleMongoRepository<T, ID> {
    private final MongoOperations mongoOperations;
    private final MongoEntityInformation<T, ID> entityInformation;


    public QuerySimpleMongoRepository(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {
        super(metadata, mongoOperations);
        this.entityInformation = metadata;
        this.mongoOperations = mongoOperations;
    }

    public <S extends T> Page<S> findAll(Query query, Class<S> clazz, Pageable pageable) {
        Assert.notNull(query, "Query must not be null!");
        Assert.notNull(pageable, "Pageable must not be null!");
        Assert.notNull(clazz, "Class must not be null!");
        query.with(pageable);
//        List<S> list = this.mongoOperations.find(query, clazz, this.entityInformation.getCollectionName());
//        return PageableExecutionUtils.getPage(list, pageable,
//                () -> mongoOperations.count(query, clazz, this.entityInformation.getCollectionName()));

        Class<S> proxyClazz  = (Class<S>) ClassUtils.getUserClass(clazz);
        List<S> list = this.mongoOperations.find(query, proxyClazz, this.entityInformation.getCollectionName());
        return PageableExecutionUtils.getPage(list, pageable,
                () -> mongoOperations.count(query, proxyClazz, this.entityInformation.getCollectionName()));
    }

    public <S extends T> Page<S> findAll(Query query, Example<S> example, Pageable pageable) {
        Assert.notNull(query, "Query must not be null!");
        Assert.notNull(pageable, "Pageable must not be null!");
        Assert.notNull(example, "Sample must not be null!");
        query.addCriteria((new Criteria()).alike(example)).with(pageable);
        List<S> list = this.mongoOperations.find(query, example.getProbeType(), this.entityInformation.getCollectionName());
        return PageableExecutionUtils.getPage(list, pageable,
                () -> mongoOperations.count(query, example.getProbeType(), this.entityInformation.getCollectionName()));
    }

    public <S extends T> List<S> findAll(Query query, Class<S> clazz) {
        Assert.notNull(query, "Query must not be null!");
        Assert.notNull(clazz, "Class must not be null!");
//        return this.mongoOperations.find(query, clazz, this.entityInformation.getCollectionName());

        Class<S> proxyClazz  = (Class<S>) ClassUtils.getUserClass(clazz);
        return this.mongoOperations.find(query, proxyClazz, this.entityInformation.getCollectionName());
    }

    public <S extends T> List<S> findAll(Query query, Example<S> example) {
        Assert.notNull(query, "Query must not be null!");
        Assert.notNull(example, "Sample must not be null!");
        query.addCriteria((new Criteria()).alike(example));
        return this.mongoOperations.find(query, example.getProbeType(), this.entityInformation.getCollectionName());
    }
}
